/// \file blockallocator.cpp.
///============================================================================\n
/// Name        : blockallocator.cpp\n
/// Author      : Gergely Lukacsy (info@dlog-reasoner.org)\n
/// Version     : 0.01\n
/// Copyright   : DERI\n
/// Description : Simple memory blockallocator, implementation file.\n
/// 
/// This file is part of the DParser and DLog 2 projects.\n
///============================================================================

// Constructor.
BLOCKALLOCATOR::BLOCKALLOCATOR(size_t nrRequestedBlockSize):
	nrBlocks(1),
	nCurrentBlock(0),
	nCurrentIndex(0) {

	DBG("Blockallocator constructor");

	// Set block size.
	nBlockSize = nrRequestedBlockSize;

	// Create the first block.
	mBlocks = new BYTE*[nrBlocks];
	mBlocks[nrBlocks-1] = new BYTE[nBlockSize];
}

// Free all memory contained within the block allocator.
BLOCKALLOCATOR::~BLOCKALLOCATOR() {

	DBG("Blockallocator destructor.");

	// Deallocate blocks.
	for (unsigned int i = 0; i < nrBlocks; ++i) {
		delete [] mBlocks[i];
	}

	// Deallocate table.
	delete [] mBlocks;
}

// Allocation.
void* BLOCKALLOCATOR::allocate(size_t nrBytesToAllocate) {
	// We never allocate more than the size of a block.
	ASSERT(nrBytesToAllocate <= nBlockSize);

	// Check if we have enough space in the current block.
	if (nCurrentIndex + nrBytesToAllocate > nBlockSize) {
		// Unfortunately we have to create a new block.
		// Request memory for the new table.
		BYTE** pNewTable = new BYTE*[nrBlocks+1];

		// Copy content of the old table to the new one
		for (unsigned int i = 0; i < nrBlocks; ++i) {
			pNewTable[i] = mBlocks[i];
		}

		// Increase number of blocks.
		nrBlocks++;

		// Request memory for the new block.
		pNewTable[nrBlocks-1] = new BYTE[nBlockSize];

		// delete old table
		delete [] mBlocks;

		// Swap tables.
		mBlocks = pNewTable;

		// Reset index
		nCurrentIndex = 0;

		// set current block
		nCurrentBlock = nrBlocks - 1;
	}

	// At this point we are sure to have enough space to allocate.

	// Create return pointer pointing to a free chunk of memory
	void* pReturn = &mBlocks[nCurrentBlock][nCurrentIndex];

	// Increment index.
	nCurrentIndex += nrBytesToAllocate;

	// Return.
	return pReturn;
}

